﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////


#include "GnufCategoryUtils.h"
#include "GnufDisplayAndPickFilterBoard.h"
#include "GnufDisplayAndPickFilterInitializerBase.h"
#include "GnufElementCanBePickedInModifyAction.h"
#include "GnufModelViewVisibilityFilterNewUtils.h"
#include "ComponentEditorCommandIds.h"
#include "GnufFilterType.h"
#include "GnufInfo.h"
#include "GnufList.h"
#include "GnufNameValuePairs.h"
#include "GnufTree.h"
#include "GnufUiCommonDef.h"
#include "IGnufProductCommonEditUIFactory.h"
#include "ICategory.h"
#include "ICategoryLibrary.h"
#include "IDocument.h"
#include "IElementCanBePickedInModifyAction.h"
#include "IElementVisibilityFilterManager.h"
#include "IModelView.h"
#include "IUiDocument.h"
#include "IUiDocumentEvent.h"
#include "IUiDocumentEventArgs.h"
#include "IUiDocumentViewManager.h"
#include "IUiView.h"
#include "IUiViewEvent.h"
#include "IUiViewEventArgs.h"
#include "IUserTransaction.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gfam;
using namespace gcmp;
using namespace gnuf;

// hard code for icon path
constexpr wchar_t* PickImagePath = L":/image/DisplayAndPickFilterTree/Pick/";
constexpr wchar_t* DisplayImagePath = L":/image/DisplayAndPickFilterTree/Display/";

const static std::wstring TREE_ROOT_CAPTION = GBMP_TR(L"所有分类");

GnufDisplayAndPickFilterBoard::GnufDisplayAndPickFilterBoard()
    : m_bInitFilterRule(false)
    , m_tree(nullptr)
    , m_nameValuePairs(nullptr)
{}

void GnufDisplayAndPickFilterBoard::Initialize(gnuf::TreeBoard* tree, gnuf::NameValuePairs* nameValuePairs)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(tree != nullptr && nameValuePairs != nullptr, L"tree或nameValuePairs为空", L"paramodel", L"2024-02-20");
    m_tree = tree;
    m_nameValuePairs = nameValuePairs;

    IGnufProductCommonEditUIFactory* pGnufProductCommonEditUIFactory = IGnufProductCommonEditUIFactory::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGnufProductCommonEditUIFactory != nullptr, L"pGnufProductCommonEditUIFactory为空", L"paramodel", L"2024-02-20");
    m_initializer = pGnufProductCommonEditUIFactory->CreateDisplayAndPickFilterInitializer();

    IUiDocumentViewManager* pUiDocumentViewManager = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocumentViewManager, L"pUiDocumentViewManager为空", L"paramodel", L"2024-02-20");

    IUiDocumentEvent * pIUiDocumentEvent = pUiDocumentViewManager->GetUiDocumentEvent();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIUiDocumentEvent, L"pIUiDocumentEvent为空", L"paramodel", L"2024-02-20");
    pIUiDocumentEvent->Add(this);

    IUiViewEvent * pIUiViewEvent = pUiDocumentViewManager->GetUiViewEvent();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIUiViewEvent, L"pIUiViewEvent为空", L"paramodel", L"2024-02-20");
    pIUiViewEvent->Add(this);
}

void GnufDisplayAndPickFilterBoard::RefreshPanel(IUiDocument* pUIDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_tree != nullptr, L"m_tree为空", L"paramodel", L"2024-02-20");

    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIDoc != nullptr, L"没有当前视图或文档", L"paramodel", L"2024-02-20");
    IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空", L"paramodel", L"2024-02-20");

    bool bIsTreeInited = false;

    if (m_tree->rawTrees().empty())
    {
        InitTree(pDoc);
    }

    //假如存在则证明是IDocument不是新建的，是切换来的
    if (GnufModelViewVisibilityFilterNewUtils::GetVisibilityFilter(pDoc) == nullptr)
    {
        OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, GBMP_TR(L"添加文档显示过滤规则"));
        DBG_WARN_AND_RETURN_VOID_UNLESS(ut != nullptr, L"ut为空", L"paramodel", L"2024-02-20");
        if (GnufModelViewVisibilityFilterNewUtils::AddVisibilityFilter(pDoc))
        {
            ut->Commit();
        }
        else
        {
            ut->Rollback();
        }
        if (!bIsTreeInited)
        {
            InitTree(pDoc);
        }
        UiInitToFilter(pDoc);
    }
    else
    {
        UiInitFromFilter(pDoc);
    }
}

void GnufDisplayAndPickFilterBoard::ClearHide(IUiDocument* pUIDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIDoc != nullptr, L"没有当前视图或文档", L"paramodel", L"2024-02-20");
    IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空", L"paramodel", L"2024-02-20");

    InitTree(pDoc);

    IElementVisibilityFilterManager* pVisibilityFiletrMgr = pDoc->GetElementVisibilityFilterManager();
    pVisibilityFiletrMgr->DeleteElementVisibilityFilter(L"");
}

void GnufDisplayAndPickFilterBoard::onTreeItemIconButtonClicked(gnuf::TreeNode* pItem, int iconIndex)
{
    using namespace gnuf;

    DBG_WARN_AND_RETURN_VOID_UNLESS(iconIndex < 3, L"超出过滤范围", L"paramodel", L"2024-02-20");
    FilterType type = static_cast<FilterType>(iconIndex);
    CheckStatus status = pItem->checkStatus(iconIndex);
    if (status == CheckStatus::Checked)
    {
        setCheckStatus(pItem, static_cast<FilterType>(iconIndex), CheckStatus::UnChecked);
    }
    else
    {
        setCheckStatus(pItem, static_cast<FilterType>(iconIndex), CheckStatus::Checked);
    }

    switch (type)
    {
    case FilterType::Pick:
        onPickIconClicked(pItem, iconIndex);
        break;
    case FilterType::Display:
        onDisplayIconClicked(pItem, iconIndex);
        break;
    default:
        break;
    }
}

void GnufDisplayAndPickFilterBoard::onDisplayIconClicked(gnuf::TreeNode* pItem, int index)
{
    using namespace gnuf;

    DBG_WARN_AND_RETURN_VOID_UNLESS(pItem != nullptr, L"pItem 为空", L"paramodel", L"2024-02-20");

    //状态刷新
    CheckStatus state = pItem->checkStatus(index);
    TreeNode* pItemParent = pItem->parentNode();
    if (pItemParent)
    {
        setFatherDisplayCheckStatusBySonCheckStatus(pItemParent, FilterType::Display, state, index);
        TreeNode* pItemGrand = pItemParent->parentNode();
        if (pItemGrand)
        {
            setFatherDisplayCheckStatusBySonCheckStatus(pItemGrand, FilterType::Display, state, index);
            TreeNode* pItemTop = pItemGrand->parentNode();
            if (pItemTop)
            {
                setFatherDisplayCheckStatusBySonCheckStatus(pItemTop, FilterType::Display, state, index);
            }
        }
    }

    if (state != CheckStatus::PartiallyChecked)
    {
        for (TreeNode* pSubItem : pItem->rawSubNodes())
        {
            setCheckStatus(pSubItem, FilterType::Display, state);
            for (TreeNode* pThirdItem : pSubItem->rawSubNodes())
            {
                setCheckStatus(pThirdItem, FilterType::Display, state);
                for (TreeNode* pForthItem : pThirdItem->rawSubNodes())
                {
                    setCheckStatus(pForthItem, FilterType::Display, state);
                }
            }
        }
    }

    //进行显示控制
    IUiDocumentViewManager* uiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(uiDocViewMgr, L"uiDocViewMgr为空", L"paramodel", L"2024-02-20");
    IUiDocument* pUIDoc = uiDocViewMgr->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIDoc != nullptr, L"没有当前视图或文档", L"paramodel", L"2024-02-20");
    IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空", L"paramodel", L"2024-02-20");
    UiInitToFilter(pDoc);

    pUIDoc->UpdateViewByVisibilityConditionChanged();
}

void GnufDisplayAndPickFilterBoard::onPickIconClicked(gnuf::TreeNode* pItem, int index)
{
    using namespace gnuf;

    IElementCanBePickedInModifyAction * IElementCanBePickedInModifyAction = IElementCanBePickedInModifyAction::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(IElementCanBePickedInModifyAction, L"IElementCanBePickedInModifyAction为空", L"paramodel", L"2024-02-20");
    ElementCanBePickedInModifyAction * pElementCanBePickedByCategoryInModifyAction = dynamic_cast<ElementCanBePickedInModifyAction *>(IElementCanBePickedInModifyAction);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementCanBePickedByCategoryInModifyAction, L"pElementCanBePickedByCategoryInModifyAction为空", L"paramodel", L"2024-02-20");

    CheckStatus state = pItem->checkStatus(index);
    setNodePickedCategory(pElementCanBePickedByCategoryInModifyAction, pItem, state);
    for (TreeNode* pSonItem : pItem->rawSubNodes())
    {
        setCheckStatus(pSonItem, FilterType::Pick, pItem->checkStatus(index));
        setNodePickedCategory(pElementCanBePickedByCategoryInModifyAction, pSonItem, state);
        for (TreeNode* pGrandSonItem : pSonItem->rawSubNodes())
        {
            setCheckStatus(pGrandSonItem, FilterType::Pick, pItem->checkStatus(index));
            setNodePickedCategory(pElementCanBePickedByCategoryInModifyAction, pGrandSonItem, state);
            for (TreeNode* pBottomLevelItem : pGrandSonItem->rawSubNodes())
            {
                setCheckStatus(pBottomLevelItem, FilterType::Pick, pItem->checkStatus(index));
                setNodePickedCategory(pElementCanBePickedByCategoryInModifyAction, pBottomLevelItem, state);
            }
        }
    }

    //根据子节点的选择，确定父节点的选择状态
    TreeNode *fatherItem = pItem->parentNode();
    if (fatherItem)
    {
        setFatherDisplayCheckStatusBySonCheckStatus(fatherItem, FilterType::Pick, state, index);
        TreeNode* grandItem = fatherItem->parentNode();
        if (grandItem)
        {
            setFatherDisplayCheckStatusBySonCheckStatus(grandItem, FilterType::Pick, state, index);
            TreeNode* topLevelItem = grandItem->parentNode();
            if (topLevelItem)
            {
                setFatherDisplayCheckStatusBySonCheckStatus(topLevelItem, FilterType::Pick, state, index);

                //能到这一层，说明点的是第四层，此时需要更改第二层的可过滤状态
                CheckStatus tmpStatus = fatherItem->checkStatus(index);
                UniIdentity parentCategoryId = FindSelectedCategoryId(fatherItem);
                if (tmpStatus == CheckStatus::Checked)
                {
                    pElementCanBePickedByCategoryInModifyAction->SetCanBePickedCategory(parentCategoryId);
                }
                else
                {
                    pElementCanBePickedByCategoryInModifyAction->SetCanNotBePickedCategory(parentCategoryId);
                }
            }
        }
    }
}

void GnufDisplayAndPickFilterBoard::setFatherDisplayCheckStatusBySonCheckStatus(TreeNode* pItemFather, FilterType filterType, const CheckStatus& state, int index)
{
    setCheckStatus(pItemFather, filterType, state);
    for (TreeNode* pChild : pItemFather->rawSubNodes())
    {
        if (state != pChild->checkStatus(index))
        {
            setCheckStatus(pItemFather, filterType, CheckStatus::PartiallyChecked);
            break;
        }
    }
}

void GnufDisplayAndPickFilterBoard::setNodePickedCategory(ElementCanBePickedInModifyAction * pElementCanBePickedByCategoryInModifyAction, gnuf::TreeNode* pItem, const gnuf::CheckStatus& state)
{
    const UniIdentity& childCategoryId = FindSelectedCategoryId(pItem);
    if (childCategoryId.IsValid())
    {
        if (state == CheckStatus::Checked)
        {
            pElementCanBePickedByCategoryInModifyAction->SetCanBePickedCategory(childCategoryId);
        }
        else if (state == CheckStatus::UnChecked)
        {
            pElementCanBePickedByCategoryInModifyAction->SetCanNotBePickedCategory(childCategoryId);
        }
        else
        {
            DBG_WARN(L"错误的选择状态！", L"paramodel", L"2024-02-20");
        }
    }
}

UniIdentity GnufDisplayAndPickFilterBoard::FindSelectedCategoryId(gnuf::TreeNode* pItem)
{
    UniIdentity categoryId = UniIdentity::InvalidUid;

    DBG_WARN_AND_RETURN_UNLESS(pItem, categoryId, L"pItem为空", L"paramodel", L"2024-02-20");
    const Info* pInfo = pItem->nodeInfo(0);
    DBG_WARN_AND_RETURN_UNLESS(pInfo, categoryId, L"pInfo为空", L"paramodel", L"2024-02-20");
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_UNLESS(pUiDocViewMgr, categoryId, L"pUiDocViewMgr为空", L"paramodel", L"2024-02-20");
    IUiDocument* pUiDoc = pUiDocViewMgr->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUiDoc, categoryId, L"pUiDoc为空", L"paramodel", L"2024-02-20");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc, categoryId, L"pDoc为空", L"paramodel", L"2024-02-20");
    ICategoryLibrary* pCategoryLibrary = ICategoryLibrary::Get(pDoc);
    DBG_WARN_AND_RETURN_UNLESS(pCategoryLibrary, categoryId, L"pCategoryLibrary为空", L"paramodel", L"2024-02-20");

    DBG_WARN_AND_RETURN_UNLESS(m_initializer, categoryId, L"m_initializer为空", L"paramodel", L"2024-02-20");
    FOR_EACH(curId, m_initializer->GetCategories(pDoc))
    {
        const ICategory* curCategory = pCategoryLibrary->GetCategory(curId);
        if (!curCategory)
            continue;

        if (pInfo->caption() == curCategory->GetName())
        {
            categoryId = curCategory->GetUniIdentity();
            break;
        }
    }

    return categoryId;
}

void GnufDisplayAndPickFilterBoard::On(gcmp::IUiDocumentEventArgs* pArgs)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pArgs, L"pArgs为空。", L"paramodel", L"2024-02-20");
    UiDocumentEventType uiEventType = pArgs->GetType();
    switch (uiEventType)
    {
    case UiDocumentEventType::UiDocumentActivated:
    {
        RefreshPanel(pArgs->GetUiDocument());
        break;
    }
    case UiDocumentEventType::PreUiDocumentClose:
    {
        ClearHide(pArgs->GetUiDocument());
        break;
    }
    }
}

void GnufDisplayAndPickFilterBoard::On(gcmp::IUiViewEventArgs* pArgs)
{
    if (pArgs->GetType() == UiViewEventType::UiViewActivated)
    {
        IUiView* pUiView = pArgs->GetUiView();
        if (pUiView)
        {
            IModelView* pModelView = pUiView->GetModelView();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"pModelView为空", L"paramodel", L"2024-02-20");
            RefreshPanel(pUiView->GetUiDocument());
        }
    }
}

void GnufDisplayAndPickFilterBoard::InitTree(IDocument* pDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pUiDoc为空", L"paramodel", L"2024-02-20");
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_initializer != nullptr, L"m_initializer为空", L"paramodel", L"2024-02-20");
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_tree != nullptr, L"m_tree为空", L"paramodel", L"2024-02-20");

    m_tree->clear();
    m_nameToCategory.clear();

    TreeNode* root = m_tree->addTree();
    root->setInfo(0, Info(TREE_ROOT_CAPTION, TREE_ROOT_CAPTION));
    root->setInfo(1, Info(L"", L"", PickImagePath), TreeNode::NodeType::eCheckBox);
    root->setInfo(2, Info(L"", L"", DisplayImagePath), TreeNode::NodeType::eCheckBox);
    m_categoryIds.clear();
    m_categoryIds = m_initializer->GetCategories(pDoc);
    const std::vector<std::wstring>& groupNames = m_initializer->GetAllGroups(pDoc);

    std::vector<std::wstring> childGroupNames;
    for (const auto& groupName : groupNames)
    {
        const std::vector<UniIdentity>& uids = m_initializer->GetCategoriesByGroupName(groupName);
        if (uids.empty())
            continue;

        AddTreeItem(pDoc, root, groupName, uids, 0, (int)uids.size());
    }

    const std::vector<UniIdentity>& categoryGroups = m_initializer->GetAllHasChildCategories(pDoc);
    if (!categoryGroups.empty())
    {
        for (TreeNode* pItemParent : m_tree->rawTrees())
        {
            if (!pItemParent)
            {
                continue;
            }

            for (TreeNode* pChild : pItemParent->rawSubNodes())
            {
                if (!pChild)
                {
                    continue;
                }

                for (TreeNode* pGrandson : pChild->rawSubNodes())
                {
                    if (!pGrandson)
                    {
                        continue;
                    }

                    if (pChild->nodeInfo(0) && pGrandson->nodeInfo(0))
                    {
                        std::wstring name = pChild->nodeInfo(0)->caption() + pGrandson->nodeInfo(0)->caption();
                        const UniIdentity& uid = GetUniIdentityByTreeItemName(name);
                        if (categoryGroups.end() != std::find(categoryGroups.begin(), categoryGroups.end(), uid))
                        {
                            AddChildTreeItem(pDoc, pGrandson, m_initializer->GetCategoriesByCategory(uid));
                        }
                    }
                }
            }
        }
    }

    for (TreeNode* pItemParent : m_tree->rawTrees())
    {
        if (!pItemParent)
        {
            continue;
        }

        setCheckStatus(pItemParent, FilterType::Pick, CheckStatus::Checked);
        setCheckStatus(pItemParent, FilterType::Display, CheckStatus::Checked);
        for (TreeNode* pChild : pItemParent->rawSubNodes())
        {
            if (!pChild)
            {
                continue;
            }

            setCheckStatus(pItemParent, FilterType::Pick, CheckStatus::Checked);
            setCheckStatus(pItemParent, FilterType::Display, CheckStatus::Checked);

            for (TreeNode* pGrandson : pChild->rawSubNodes())
            {
                if (!pGrandson)
                {
                    continue;
                }

                setCheckStatus(pItemParent, FilterType::Pick, CheckStatus::Checked);
                setCheckStatus(pItemParent, FilterType::Display, CheckStatus::Checked);
            }
        }
    }
    m_tree->expandAll();
}

void GnufDisplayAndPickFilterBoard::AddTreeItem(IDocument* pDoc, gnuf::TreeNode* pItem, const std::wstring& name, const std::vector<UniIdentity>& categoryIds, int startIndex, int endIndex)
{
    using namespace gnuf;

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_initializer != nullptr, L"m_initializer为空", L"paramodel", L"2024-02-20");
    DBG_WARN_AND_RETURN_VOID_UNLESS(startIndex <= endIndex, L"startIndex不能比endIndex大", L"paramodel", L"2024-02-20");

    TreeNode* root = pItem->addSubNode();
    root->setInfo(0, Info(name, name));
    root->setInfo(1, Info(L"", L"", PickImagePath), TreeNode::NodeType::eCheckBox);
    root->setInfo(2, Info(L"", L"", DisplayImagePath), TreeNode::NodeType::eCheckBox);

    const ICategoryLibrary* pCategoryLibaryConst = ICategoryLibrary::Get(pDoc);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCategoryLibaryConst != nullptr, L"pCategoryLibaryConst为空", L"paramodel", L"2024-02-20");
    const IUidTree* pUidTree = pCategoryLibaryConst->GetCategoryUidTree();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUidTree != nullptr, L"pUidTree为空", L"paramodel", L"2024-02-20");

    std::map<std::wstring, TreeNode*> nameToTreeItemId;
    for (int i = startIndex; i < endIndex; ++i)
    {
        std::wstring tempName = name;
        if (i >= categoryIds.size())
            continue;

        UniIdentity categoryUid = categoryIds[i];
        const ICategory* curCategory = pCategoryLibaryConst->GetCategory(categoryUid);
        if (curCategory == nullptr)
            continue;

        std::wstring iconPath = m_initializer->GetCategoryIcon(categoryUid);
        iconPath = iconPath.empty() ? L":/image/DisplayAndPickFilterTree" : iconPath;
        if (CategoryUtils::IsTopCategory(pUidTree, categoryIds[i]))
        {
            TreeNode *childitem = root->addSubNode();
            if (childitem)
            {
                childitem->setInfo(0, Info(curCategory->GetName(), curCategory->GetName(), iconPath));
                childitem->setInfo(1, Info(L"", L"", PickImagePath), TreeNode::NodeType::eCheckBox);
                childitem->setInfo(2, Info(L"", L"", DisplayImagePath), TreeNode::NodeType::eCheckBox);
            }
            tempName.append(curCategory->GetName());
            nameToTreeItemId[curCategory->GetName()] = childitem;
            m_nameToCategory.insert(std::pair<std::wstring, UniIdentity>(tempName, categoryUid));
        }
        else
        {
            const UniIdentity& topCategoryUid = CategoryUtils::GetTopCategory(pUidTree, categoryUid);
            const ICategory* topCategory = pCategoryLibaryConst->GetCategory(topCategoryUid);
            if (topCategory == nullptr)
            {
                TreeNode *childitem = root->addSubNode();
                if (childitem)
                {
                    childitem->setInfo(0, Info(curCategory->GetName(), curCategory->GetName(), iconPath));
                    childitem->setInfo(1, Info(L"", L"", PickImagePath), TreeNode::NodeType::eCheckBox);
                    childitem->setInfo(2, Info(L"", L"", DisplayImagePath), TreeNode::NodeType::eCheckBox);
                }
                tempName.append(curCategory->GetName());
                m_nameToCategory.insert(std::pair<std::wstring, UniIdentity>(tempName, categoryUid));
            }
            else
            {
                std::wstring topCategoryName = topCategory->GetName();
                auto it = nameToTreeItemId.find(topCategoryName);
                if (it != nameToTreeItemId.end())
                {
                    TreeNode *topCategoryItem = it->second;
                    if (!topCategoryItem)
                    {
                        continue;
                    }

                    TreeNode *childitem = topCategoryItem->addSubNode();
                    if (childitem)
                    {
                        childitem->setInfo(0, Info(curCategory->GetName(), curCategory->GetName(), iconPath));
                        childitem->setInfo(1, Info(L"", L"", PickImagePath), TreeNode::NodeType::eCheckBox);
                        childitem->setInfo(2, Info(L"", L"", DisplayImagePath), TreeNode::NodeType::eCheckBox);
                    }
                    tempName.append(curCategory->GetName());
                    m_nameToCategory.insert(std::pair<std::wstring, UniIdentity>(tempName, categoryUid));
                }
            }
        }
    }
}

void GnufDisplayAndPickFilterBoard::AddChildTreeItem(IDocument* pDoc, gnuf::TreeNode* pItem, const std::vector<UniIdentity>& categoryIds)
{
    using namespace gnuf;

    DBG_WARN_AND_RETURN_VOID_UNLESS(pItem, L"pItem为空", L"paramodel", L"2024-02-20");
    const TreeNode* pParentNode = pItem->parentNode();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParentNode, L"pParentNode为空", L"paramodel", L"2024-02-20");
    const Info* pInfo = pParentNode->nodeInfo(0);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pInfo, L"pInfo为空", L"paramodel", L"2024-02-20");

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_initializer != nullptr, L"m_initializer为空", L"paramodel", L"2024-02-20");
    const ICategoryLibrary* pCategoryLibaryConst = ICategoryLibrary::Get(pDoc);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCategoryLibaryConst != nullptr, L"pCategoryLibaryConst为空", L"paramodel", L"2024-02-20");
    const IUidTree* pUidTree = pCategoryLibaryConst->GetCategoryUidTree();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUidTree != nullptr, L"pUidTree为空", L"paramodel", L"2024-02-20");

    std::map<std::wstring, TreeNode*> nameToTreeItemId;
    FOR_EACH(uid, categoryIds)
    {
        const ICategory* curCategory = pCategoryLibaryConst->GetCategory(uid);
        if (curCategory == nullptr)
            continue;

        std::wstring tempName = pInfo->caption();
        std::wstring iconPath = m_initializer->GetCategoryIcon(uid);
        iconPath = iconPath.empty() ? L":/image/DisplayAndPickFilterTree" : iconPath;
        if (CategoryUtils::IsTopCategory(pUidTree, uid))
        {
            TreeNode *childitem = pItem->addSubNode();
            childitem->setInfo(0, Info(curCategory->GetName(), curCategory->GetName(), iconPath));
            childitem->setInfo(1, Info(L"", L"", PickImagePath), TreeNode::NodeType::eCheckBox);
            childitem->setInfo(2, Info(L"", L"", DisplayImagePath), TreeNode::NodeType::eCheckBox);
            tempName.append(curCategory->GetName());
            nameToTreeItemId[curCategory->GetName()] = childitem;
            m_nameToCategory.insert(std::pair<std::wstring, UniIdentity>(tempName, uid));
        }
        else
        {
            const UniIdentity& topCategoryUid = CategoryUtils::GetTopCategory(pUidTree, uid);
            const ICategory* topCategory = pCategoryLibaryConst->GetCategory(topCategoryUid);
            if (topCategory == nullptr)
            {
                TreeNode *childitem = pItem->addSubNode();
                childitem->setInfo(0, Info(curCategory->GetName(), curCategory->GetName(), iconPath));
                childitem->setInfo(1, Info(L"", L"", PickImagePath), TreeNode::NodeType::eCheckBox);
                childitem->setInfo(2, Info(L"", L"", DisplayImagePath), TreeNode::NodeType::eCheckBox);
                tempName.append(curCategory->GetName());
                m_nameToCategory.insert(std::pair<std::wstring, UniIdentity>(tempName, uid));
            }
            else
            {
                std::wstring topCategoryName = topCategory->GetName();
                auto it = nameToTreeItemId.find(topCategoryName);
                if (it != nameToTreeItemId.end())
                {
                    TreeNode *topCategoryItem = it->second;
                    if (!topCategoryItem)
                    {
                        continue;
                    }

                    TreeNode *childitem = topCategoryItem->addSubNode();
                    childitem->setInfo(0, Info(curCategory->GetName(), curCategory->GetName(), iconPath));
                    childitem->setInfo(1, Info(L"", L"", PickImagePath), TreeNode::NodeType::eCheckBox);
                    childitem->setInfo(2, Info(L"", L"", DisplayImagePath), TreeNode::NodeType::eCheckBox);
                    tempName.append(curCategory->GetName());
                    m_nameToCategory.insert(std::pair<std::wstring, UniIdentity>(tempName, uid));
                }
            }
        }
    }
}

UniIdentity GnufDisplayAndPickFilterBoard::GetUniIdentityByTreeItemName(const std::wstring& name)
{
    auto it = m_nameToCategory.find(name);
    if (it != m_nameToCategory.end())
    {
        return it->second;
    }
    else
    {
        return UniIdentity::InvalidUid;
    }
}

void GnufDisplayAndPickFilterBoard::UiInitFromFilter(IDocument* pDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_tree != nullptr, L"m_tree为空", L"paramodel", L"2024-02-20");

    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr, L"pUiDocViewMgr为空", L"paramodel", L"2024-02-20");

    IUiView* pUiView = pUiDocViewMgr->GetCurrentUiView();
    if (pUiView == nullptr)
        return;

    IModelView* pModelView = pUiView->GetModelView();
    if (pModelView == nullptr)
        return;

    using namespace gnuf;

    TreeNode* pRoot = nullptr;
    for (TreeNode* pItem : m_tree->rawTrees())
    {
        if (!pItem)
        {
            continue;
        }

        if (!pItem->nodeInfo(0))
        {
            continue;
        }

        if (TREE_ROOT_CAPTION == pItem->nodeInfo(0)->caption())
        {
            pRoot = pItem;
            break;
        }
    }
    DBG_WARN_AND_RETURN_VOID_UNLESS(pRoot, L"pRoot为空", L"paramodel", L"2024-02-20");

    for (TreeNode* pItemParent : pRoot->rawSubNodes())
    {
        if (!pItemParent)
        {
            continue;
        }

        if (!pItemParent->nodeInfo(0))
        {
            continue;
        }

        const std::wstring& name = pItemParent->nodeInfo(0)->caption();
        int checkCount = 0;
        int uncheckCount = 0;
        for (TreeNode* pChild : pItemParent->rawSubNodes())
        {
            if (!pChild)
            {
                continue;
            }

            if (!pChild->nodeInfo(0))
            {
                continue;
            }

            std::wstring nameChild = pChild->nodeInfo(0)->caption();
            std::wstring tmpName = name;
            tmpName.append(nameChild);

            if (pChild->rawSubNodes().empty())
            {
                const UniIdentity& id = GetUniIdentityByTreeItemName(tmpName);
                bool isExist = GnufModelViewVisibilityFilterNewUtils::IsCategoryExistInFilter(pDoc, pModelView->GetElementId(), id);
                if (isExist)
                {
                    setCheckStatus(pChild, FilterType::Display, CheckStatus::UnChecked);
                    uncheckCount++;
                }
                else
                {
                    setCheckStatus(pChild, FilterType::Display, CheckStatus::Checked);
                    checkCount++;
                }
            }
            else
            {
                int grandsonCheckCount = 0;
                int grandsonUnCheckCount = 0;
                for (TreeNode* pGrandson : pChild->rawSubNodes())
                {
                    if (!pGrandson)
                    {
                        continue;
                    }

                    if (!pGrandson->nodeInfo(0))
                    {
                        continue;
                    }

                    nameChild = pGrandson->nodeInfo(0)->caption();
                    tmpName = name;
                    tmpName.append(nameChild);

                    const UniIdentity& id = GetUniIdentityByTreeItemName(tmpName);
                    bool isExist = GnufModelViewVisibilityFilterNewUtils::IsCategoryExistInFilter(pDoc, pModelView->GetElementId(), id);
                    if (isExist)
                    {
                        setCheckStatus(pGrandson, FilterType::Display, CheckStatus::UnChecked);
                        grandsonUnCheckCount++;
                    }
                    else
                    {
                        setCheckStatus(pGrandson, FilterType::Display, CheckStatus::Checked);
                        grandsonCheckCount++;
                    }
                }

                if (grandsonCheckCount == pChild->rawSubNodes().size())
                {
                    setCheckStatus(pChild, FilterType::Display, CheckStatus::Checked);
                    checkCount++;
                }
                else if (grandsonUnCheckCount == pChild->rawSubNodes().size())
                {
                    setCheckStatus(pChild, FilterType::Display, CheckStatus::UnChecked);
                    uncheckCount++;
                }
                else
                {
                    setCheckStatus(pChild, FilterType::Display, CheckStatus::PartiallyChecked);
                }
            }
        }

        setCheckStatus(pItemParent, FilterType::Display, CheckStatus::PartiallyChecked);
        if (uncheckCount == pItemParent->rawSubNodes().size())
        {
            setCheckStatus(pItemParent, FilterType::Display, CheckStatus::UnChecked);
        }
        if (checkCount == pItemParent->rawSubNodes().size())
        {
            setCheckStatus(pItemParent, FilterType::Display, CheckStatus::Checked);
        }
    }
}

void GnufDisplayAndPickFilterBoard::UiInitToFilter(IDocument* pDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_tree != nullptr, L"m_tree为空", L"paramodel", L"2024-02-20");

    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr, L"pUiDocViewMgr为空", L"paramodel", L"2024-02-20");

    IUiView* pUiView = pUiDocViewMgr->GetCurrentUiView();
    if (pUiView == nullptr)
        return;

    IModelView* pModelView = pUiView->GetModelView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"pModelView为空", L"paramodel", L"2024-02-20");
    using namespace gnuf;

    TreeNode* pRoot = nullptr;
    for (TreeNode* pItem : m_tree->rawTrees())
    {
        if (!pItem)
        {
            continue;
        }

        if (!pItem->nodeInfo(0))
        {
            continue;
        }

        if (TREE_ROOT_CAPTION == pItem->nodeInfo(0)->caption())
        {
            pRoot = pItem;
            break;
        }
    }
    DBG_WARN_AND_RETURN_VOID_UNLESS(pRoot, L"pRoot为空", L"paramodel", L"2024-02-20");

    for (TreeNode* pItemParent : pRoot->rawSubNodes())
    {
        if (!pItemParent)
        {
            continue;
        }

        if (!pItemParent->nodeInfo(0))
        {
            continue;
        }

        const std::wstring& parentName = pItemParent->nodeInfo(0)->caption();

        for (TreeNode* pChild : pItemParent->rawSubNodes())
        {
            if (!pChild)
            {
                continue;
            }

            if (!pChild->nodeInfo(0))
            {
                continue;
            }

            std::wstring name = parentName;
            const std::wstring& nameChild = pChild->nodeInfo(0)->caption();
            name.append(nameChild);

            const UniIdentity& id = GetUniIdentityByTreeItemName(name);
            if (id.IsValid())
            {
                std::vector<UniIdentity> ids;
                ids.push_back(id);

                for (int i = 0; i < ids.size(); i++)
                {
                    if (CheckStatus::Checked == pChild->checkStatus(static_cast<int>(FilterType::Display)))
                    {
                        GnufModelViewVisibilityFilterNewUtils::RemoveCategoryFromFilter(pDoc, pModelView->GetElementId(), ids.at(i));
                    }
                    else if (CheckStatus::UnChecked == pChild->checkStatus(static_cast<int>(FilterType::Display)))
                    {
                        GnufModelViewVisibilityFilterNewUtils::AddCategoryToFilter(pDoc, pModelView->GetElementId(), ids.at(i));
                    }
                }
            }

            for (TreeNode* pSendoaryItem : pChild->rawSubNodes())
            {
                if (pSendoaryItem == nullptr)
                {
                    continue;
                }

                if (!pSendoaryItem->nodeInfo(0))
                {
                    continue;
                }

                std::wstring nameSecondary = parentName;
                nameSecondary.append(pSendoaryItem->nodeInfo(0)->caption());
                const UniIdentity& id = GetUniIdentityByTreeItemName(nameSecondary);
                if (CheckStatus::Checked == pSendoaryItem->checkStatus(static_cast<int>(FilterType::Display)))
                {
                    GnufModelViewVisibilityFilterNewUtils::RemoveCategoryFromFilter(pDoc, pModelView->GetElementId(), id);
                }
                else if (CheckStatus::UnChecked == pSendoaryItem->checkStatus(static_cast<int>(FilterType::Display)))
                {
                    GnufModelViewVisibilityFilterNewUtils::AddCategoryToFilter(pDoc, pModelView->GetElementId(), id);
                }
                for (TreeNode* pThirdItem : pSendoaryItem->rawSubNodes())
                {
                    if (pThirdItem == nullptr)
                    {
                        continue;
                    }

                    if (pThirdItem->nodeInfo(0) == nullptr)
                    {
                        continue;
                    }

                    std::wstring nameThird = parentName;
                    nameThird.append(pThirdItem->nodeInfo(0)->caption());
                    const UniIdentity& id = GetUniIdentityByTreeItemName(nameThird);
                    if (CheckStatus::Checked == pThirdItem->checkStatus(static_cast<int>(FilterType::Display)))
                    {
                        GnufModelViewVisibilityFilterNewUtils::RemoveCategoryFromFilter(pDoc, pModelView->GetElementId(), id);
                    }
                    else if (CheckStatus::UnChecked == pThirdItem->checkStatus(static_cast<int>(FilterType::Display)))
                    {
                        GnufModelViewVisibilityFilterNewUtils::AddCategoryToFilter(pDoc, pModelView->GetElementId(), id);
                    }
                }
            }
        }
    }
}

void GnufDisplayAndPickFilterBoard::setCheckStatus(gnuf::TreeNode* node, FilterType filterType, gnuf::CheckStatus status)
{
    using namespace gnuf;

    DBG_WARN_AND_RETURN_VOID_UNLESS(node != nullptr, L"node不能为空!", L"paramodel", L"2024-02-20");
    node->setCheckStatus(static_cast<int>(filterType), status);
}